package com.hyper_yang.javase.multiThread;

/*
多线程并发访问统一资源，因为线程的并发性，所以会导致数据不一致的问题
要依靠锁来解决并发问题，同一时刻，能操作共享数据的只能是一个线程，其他线程处于阻塞状态

synchronized:
    同步代码块:
        synchronized(锁对象){}
        可以灵活的指定锁对象是谁，只要是共享独立的资源
    同步方法:
        public synchronized 返回值类型 方法名(){}
同步代码块在上锁时，要指定锁对象。
同步方法在上锁时，锁的是当前方法所归属的类的对象  this
 */
public class Thread_safe_lockBlock {
    public static void main(String[] args) {
//        WindowRunnable windowRunnable = new WindowRunnable();
//        Thread w1 = new Thread(windowRunnable, "窗口1");
//        Thread w2 = new Thread(windowRunnable, "窗口2");
//        Thread w3 = new Thread(windowRunnable, "窗口3");
//
//        w1.start();
//        w2.start();
//        w3.start();

        System.out.println("=================================================");

        WindowThread t1= new WindowThread("窗口1");
        WindowThread t2= new WindowThread("窗口2");
        WindowThread t3= new WindowThread("窗口3");

        t1.start();
        t2.start();
        t3.start();
    }
}

class WindowRunnable implements Runnable {
    int tickets = 100; // 如果是局部变量（写在 run方法里的话每个线程都会卖 100张）

    @Override
    public void run() {
        while (true) {
            // 锁: 一定要是共享资源。 为什么不锁 tickets? int基本类型没有锁
            synchronized (this) { // 【上锁】 字符串“AAA”等只有一份的数据也可以
                if (tickets <= 0) {
                    System.out.println("票卖完了！！！");
                    break;
                }
                try {
                    Thread.sleep(20); // 模拟出票过程
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                tickets--;
                System.out.println(Thread.currentThread().getName() + "卖了一张票，剩余" + tickets + "张票");
            }
        }
    }
}

class WindowThread extends Thread {
    public WindowThread(String name) {
        super(name);
    }

    // static 类属性，该类的所有对象共享
    static int tickets = 100; // 区别于 runnable,否则一个窗口 100张
    // 自定义一个静态对象充当锁  其实也可以写 “AAA”
    static Object lock = new Object();

    @Override
    public void run() {
        while (true) {
            synchronized (lock) { // 区别于 runnable的 this,因为 runnable只有一个对象，而这三个线程的 this不一致
                if (tickets <= 0) {
                    System.out.println("票卖完了！！！");
                    break;
                }
                try {
                    Thread.sleep(20); // 模拟出票过程
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                tickets--;
                System.out.println(Thread.currentThread().getName() + "卖了一张票，剩余" + tickets + "张票");
            }
        }
    }
}